package io.nobug;

import io.nobug.exception.KeyNotExistException;

import java.awt.*;
import java.awt.event.InputEvent;
import java.util.Optional;

import static io.nobug.core.KeyMapHolder.MAP;

/**
 * 核心操作类，涵盖多种键鼠操作
 *
 * @author db1995
 */
public class Actor {
    private final Robot ROBOT = new Robot();

    /**
     * 按键间隔默认为1秒
     *
     * @throws AWTException
     */
    private Actor() throws AWTException {
        this(1000);
    }

    /**
     * 自定义按键间隔
     *
     * @param ms 按键间隔（毫秒）
     * @throws AWTException
     */
    private Actor(int ms) throws AWTException {
        ROBOT.setAutoDelay(ms / 2);
    }

    /**
     * 以默认操作间隔1秒初始化
     *
     * @return
     * @throws AWTException
     */
    public static Actor init() throws AWTException {
        return new Actor(1000);
    }

    /**
     * 以自定义操作间隔初始化
     *
     * @param ms 按键间隔（毫秒）
     * @return
     * @throws AWTException
     */
    public static Actor init(int ms) throws AWTException {
        return new Actor(ms);
    }

    /**
     * 设置按键间隔
     *
     * @param ms 按键间隔（毫秒）
     */
    public Actor autoDelay(int ms) {
        ROBOT.setAutoDelay(ms);
        return this;
    }

    /**
     * 移动鼠标
     *
     * @param x 屏幕横坐标
     * @param y 屏幕纵坐标
     */
    public Actor move(int x, int y) {
        ROBOT.mouseMove(x, y);
        return this;
    }

    /**
     * 依次执行按键（有按键间隔）
     *
     * @param keys 一系列按键，如keys("a", "p", "p", "l", "e")
     */
    public Actor keys(String... keys) {
        upper(keys);
        for (String key : keys) {
            Integer code = MAP.get(key);
            ROBOT.keyPress(Optional.ofNullable(code).orElseThrow(() -> new KeyNotExistException(key)));
            ROBOT.keyRelease(code);
        }
        return this;
    }

    /**
     * 依次执行按键（有按键间隔）
     *
     * @param keys 一系列按键，如keys("a p p l e")
     */
    public Actor keys(String keys) {
        return keys(keys.split(" "));
    }

    /**
     * 依次执行按键（有按键间隔），先import static java.awt.event.KeyEvent.*;
     *
     * @param keys 一系列按键，如keys(VK_A, VK_P, VK_P, VK_L, VK_E)
     */
    public Actor keys(int... keys) {
        for (int key : keys) {
            ROBOT.keyPress(key);
            ROBOT.keyRelease(key);
        }
        return this;
    }

    /**
     * 组合按键
     *
     * @param keys 一系列按键，如combo("ctrl", "c")
     */
    public Actor combo(String... keys) {
        upper(keys);
        for (String key : keys) {
            Integer code = MAP.get(key);
            ROBOT.keyPress(Optional.ofNullable(code).orElseThrow(() -> new KeyNotExistException(key)));
        }
        for (String key : keys) {
            ROBOT.keyRelease(MAP.get(key));
        }
        return this;
    }

    /**
     * 组合按键
     *
     * @param keys 一系列按键，如combo("ctrl c")
     */
    public Actor combo(String keys) {
        return combo(keys.split(" "));
    }

    /**
     * 组合按键，先import static java.awt.event.KeyEvent.*;
     *
     * @param keys 一系列按键，如combo(VK_CTRL, VK_C)
     */
    public Actor combo(int... keys) {
        for (int key : keys) {
            ROBOT.keyPress(key);
        }
        for (int key : keys) {
            ROBOT.keyRelease(key);
        }
        return this;
    }

    /**
     * 延迟等待
     *
     * @param ms 毫秒
     */
    public Actor delay(int ms) {
        ROBOT.delay(ms);
        return this;
    }

    /**
     * 单击鼠标左键
     */
    public Actor clickL() {
        ROBOT.mousePress(InputEvent.BUTTON1_MASK);
        ROBOT.mouseRelease(InputEvent.BUTTON1_MASK);
        return this;
    }

    /**
     * 移动鼠标后单击鼠标左键
     *
     * @param x 屏幕横坐标
     * @param y 屏幕纵坐标
     */
    public Actor clickL(int x, int y) {
        ROBOT.mouseMove(x, y);
        clickL();
        return this;
    }

    /**
     * 双击鼠标左键
     */
    public Actor doubleL() {
        ROBOT.mousePress(InputEvent.BUTTON1_MASK);
        ROBOT.mouseRelease(InputEvent.BUTTON1_MASK);
        ROBOT.mousePress(InputEvent.BUTTON1_MASK);
        ROBOT.mouseRelease(InputEvent.BUTTON1_MASK);
        return this;
    }

    /**
     * 移动鼠标后双击鼠标左键
     *
     * @param x 屏幕横坐标
     * @param y 屏幕纵坐标
     */
    public Actor doubleL(int x, int y) {
        ROBOT.mouseMove(x, y);
        doubleL();
        return this;
    }

    /**
     * 单击鼠标右键
     */
    public Actor clickR() {
        ROBOT.mousePress(InputEvent.BUTTON3_MASK);
        ROBOT.mouseRelease(InputEvent.BUTTON3_MASK);
        return this;
    }

    /**
     * 移动鼠标后单击鼠标右键
     *
     * @param x 屏幕横坐标
     * @param y 屏幕纵坐标
     */
    public Actor clickR(int x, int y) {
        ROBOT.mouseMove(x, y);
        clickR();
        return this;
    }

    /**
     * 单击鼠标中键
     */
    public Actor clickM() {
        ROBOT.mousePress(InputEvent.BUTTON2_MASK);
        ROBOT.mouseRelease(InputEvent.BUTTON2_MASK);
        return this;
    }

    /**
     * 移动鼠标后单击鼠标中键
     *
     * @param x 屏幕横坐标
     * @param y 屏幕纵坐标
     */
    public Actor clickM(int x, int y) {
        ROBOT.mouseMove(x, y);
        clickM();
        return this;
    }

    /**
     * 滚动鼠标中键
     *
     * @param scale 滚轮的刻度，如3表示向下滚动3格，-2表示向上滚动2格
     */
    public Actor scrollM(int scale) {
        ROBOT.mouseWheel(scale);
        return this;
    }

    /**
     * 移动鼠标后滚动鼠标中键
     *
     * @param x     屏幕横坐标
     * @param y     屏幕纵坐标
     * @param scale 滚轮的刻度，如3表示向下滚动3格，-2表示向上滚动2格
     */
    public Actor scrollM(int x, int y, int scale) {
        ROBOT.mouseMove(x, y);
        scrollM(scale);
        return this;
    }

    /**
     * 从当前点开始按住鼠标左键拖动
     *
     * @param x 终点横坐标
     * @param y 终点纵坐标
     */
    public Actor drag(int x, int y) {
        ROBOT.mousePress(InputEvent.BUTTON1_MASK);
        ROBOT.mouseMove(x, y);
        ROBOT.mouseRelease(InputEvent.BUTTON1_MASK);
        return this;
    }

    /**
     * 从某坐标开始按住鼠标左键拖动
     *
     * @param startX 起点横坐标
     * @param startY 起点纵坐标
     * @param endX   终点横坐标
     * @param endY   终点纵坐标
     */
    public Actor drag(int startX, int startY, int endX, int endY) {
        ROBOT.mouseMove(startX, startY);
        drag(endX, endY);
        return this;
    }

    /**
     * 转大写
     *
     * @param array 需要处理的字符串数组
     */
    private void upper(String[] array) {
        for (int i = 0; i < array.length; i++) {
            array[i] = array[i].toUpperCase();
        }
    }
}
